unit MCAccess;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Menus, StdCtrls, TitrDefs, Solver, TiUncertain, Editor, Grids,
  ExtCtrls, TeeProcs, TeEngine, Chart, Series;

type
  TMCForm = class(TForm)
    Label1: TLabel;
    MainMenu1: TMainMenu;
    File1: TMenuItem;
    Calculate1: TMenuItem;
    Help1: TMenuItem;
    Exit1: TMenuItem;
    SinglePointMC1: TMenuItem;
    Surface1: TMenuItem;
    SensitivityMatrix1: TMenuItem;
    SaveDialog1: TSaveDialog;
    Label2: TLabel;
    RepsEdit: TEdit;
    Label5: TLabel;
    Label25: TLabel;
    RandEdit: TEdit;
    AutoSaveBox: TCheckBox;
    AutoNameEdit: TEdit;
    Label33: TLabel;
    StatGrid: TStringGrid;
    Label3: TLabel;
    Bevel1: TBevel;
    AutoSaveStatBox: TCheckBox;
    Label4: TLabel;
    StatsNameEdit: TEdit;
    Bevel2: TBevel;
    Label6: TLabel;
    Label7: TLabel;
    DiffXEdit: TEdit;
    AutoSaveSensBox: TCheckBox;
    Label8: TLabel;
    SensFileNameEdit: TEdit;
    HistoChart: TChart;
    Series1: TBarSeries;
    Label9: TLabel;
    GraphSelect: TComboBox;
    Label10: TLabel;
    SaveSensitivityMatrix1: TMenuItem;
    SaveMonteCarloResults1: TMenuItem;
    SaveMonteCarloStatistics1: TMenuItem;
    Exit2: TMenuItem;
    FullMCBtn: TButton;
    OneVarMCBtn: TButton;
    SensMatBtn: TButton;
    Label11: TLabel;
    SingleMCSelect: TComboBox;
    SingleConstraintMC1: TMenuItem;
    procedure Exit1Click(Sender: TObject);
    procedure Help1Click(Sender: TObject);
    procedure RepsEditExit(Sender: TObject);
    procedure RandEditExit(Sender: TObject);
    procedure AutoSaveBoxClick(Sender: TObject);
    procedure AutoNameEditExit(Sender: TObject);
    procedure SinglePointMC1Click(Sender: TObject);
    procedure FormActivate(Sender: TObject);
    procedure SensitivityMatrix1Click(Sender: TObject);
    procedure Surface1Click(Sender: TObject);
    procedure DiffXEditExit(Sender: TObject);
    procedure AutoSaveStatBoxClick(Sender: TObject);
    procedure AutoSaveSensBoxClick(Sender: TObject);
    procedure StatsNameEditExit(Sender: TObject);
    procedure SensFileNameEditExit(Sender: TObject);
    procedure GraphSelectChange(Sender: TObject);
    procedure SaveSensitivityMatrix1Click(Sender: TObject);
    procedure SingleMCSelectChange(Sender: TObject);
    procedure OneVarMCBtnClick(Sender: TObject);
    procedure SaveMonteCarloResults1Click(Sender: TObject);
    procedure SaveMonteCarloStatistics1Click(Sender: TObject);
  
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  MCForm: TMCForm;

implementation

uses TitrHelp;

{$R *.dfm}

{WriteScreen fills in the edit boxes, check boxes and title label with }
{appropriate material.}

Procedure WriteScreen;

Var  com, spe, i : integer;

begin
      MCDone := False;                       {no MC calculation done yet}
      SensDone := False;                     {no sensitivity calculation yet}

   With MCForm do begin
      {Initialize various GUI display variables}
      Label1.Caption := S.Head.Title;
      AutoNameEdit.Text := MonteFileBase;
      RandEdit.Text := IntToStr(RSeed);
      AutoSaveBox.Checked := MCSave;
      AutoSaveStatBox.Checked := MCStatSave;
      StatsNameEdit.Text := MonteStatFileBase;
      AutoSaveSensBox.Checked := SensSave;
      SensFileNameEdit.Text := Sensfile;
      DiffXEdit.Text := FloatToStrF(DiffX, ffFixed, 8, 3);
      RepsEdit.Text := IntToStr(MCReps);

      {Initialize combo-box for selecting a concentration to graph}
      GraphSelect.Items.Clear;
      GraphSelect.Items.Add('None selected');
      For com := 1 to S.NComp do
         i := GraphSelect.Items.add(S.Comps[com].Name);
      For spe := 1 to S.NSpec do
         i := GraphSelect.Items.add(S.Specs[spe].Name);
      GraphSelect.ItemIndex := 0;

      {Initialize selection box for single-constraint Monte Carlo}
      SingleMCSelect.Items := GraphSelect.Items;
      SingleMCSelect.ItemIndex := 0;
      OneCon := False;                      {default is full MC simulation}

   end;

end;                                    {end of initialization}

{ClearGraph deletes any existing data from the histogram display and resets }
{selection box to 'no species selected'}

Procedure ClearGraph;

begin
   With MCForm do begin
     Series1.Clear;
     GraphSelect.ItemIndex := 0;
    end;
end;

{WriteStatGrid writes the names of chemical species and their summary }
{statistics into the StringGrid StatGrid}

Procedure WriteStatGrid(Values :Boolean);

Var  com, spe : integer;    {counter indices}
     Stat : StatType;

begin
   {First make sure grid is the correct size}
   MCForm.StatGrid.RowCount := 6;
   MCForm.StatGrid.ColCount := S.NSpec + S.Ncomp + 1;
   MCForm.Label9.Caption := 'Monte Carlo Summary';

   {Next write the species names in the top row}
   For com := 1 to S.NComp do
       MCForm.StatGrid.Cells[com, 0] := S.Comps[com].Name;
   For spe := 1 to S.NSpec do
       MCForm.StatGrid.Cells[spe + S.NComp, 0] := S.Specs[spe].Name;

   {Next write the Statistics names into the first column}
   For Stat := TrueValue to Kurtosis do
       MCForm.StatGrid.Cells[0,integer(Stat)+1] := StatStrings[Stat];

   {Finally write the descriptive statistics into the grid}
   For spe := 1 to (S.NComp + S.NSpec) do
     For Stat := TrueValue to Kurtosis do
       If (Values) then
         MCForm.StatGrid.Cells[spe, integer(Stat) + 1] :=
          FloatToStrF(MCPointSum[spe, Stat], ffFixed, 8, 3)
          else  MCForm.StatGrid.Cells[spe, integer(Stat) + 1] :=  '';
   end;

{WriteSensMat writes the names of chemical species and their log/log derivatives
{StringGrid StatGrid}

Procedure WriteSensMat(Var SensMat : SensiMat; NConc : integer);

Var  com, spe : integer;    {counter indices}

begin
   {First make sure grid is the correct size}
   MCForm.StatGrid.RowCount := NConc + 1;
   MCForm.StatGrid.ColCount := NConc + 1;
   MCForm.Label9.Caption := 'Sensitivity Matrix';

   {Next write the species names in the top row and the left side}
   For com := 1 to S.NComp do begin
       MCForm.StatGrid.Cells[com, 0] := S.Comps[com].Name;
       MCForm.StatGrid.Cells[0, com] := S.Comps[com].name;
     end;
   For spe := 1 to S.NSpec do begin
       MCForm.StatGrid.Cells[spe + S.NComp, 0] := S.Specs[spe].Name;
       MCForm.StatGrid.Cells[0, spe + S.NComp] := S.Specs[spe].Name;
     end;

  {Finally write the derivatives into the grid}
   For spe := 1 to NConc do
     For com := 1 to NConc do
       MCForm.StatGrid.Cells[spe, com] :=
          FloatToStrF(SensMat[com, spe], ffFixed, 8, 3);
   end;                                          {End of WriteSensMat}

{Exit1Click closes the form, returning to the system definition screen}

procedure TMCForm.Exit1Click(Sender: TObject);      {standard exit from form}
begin
   MCForm.Close;
end;

{Help form displayed, defaulting to the Monte Carlo page}

procedure TMCForm.Help1Click(Sender: TObject);      {shows help screen}
begin
    HelpIndex := 17;
    TitrHelpForm.ShowModal;
end;

{RepsEdit allows the user to specify the number of trials in a MC simulation}

procedure TMCForm.RepsEditExit(Sender: TObject);
begin
   RepsEdit.Text := WriteIntEdit(RepsEdit.Text, MCReps, 3, MaxMCReps);
end;

{ RandEdit is used to enter a seed value for the random number generator}

procedure TMCForm.RandEditExit(Sender: TObject);
   Var   code : integer;
begin
  code := BoundStr2Int(RandEdit.Text, RSeed, 1, 10000000);
  RandEdit.Text := IntToStr(RSeed);
end;

{ If the AutoSaveBox is checked then MC results files are saved automatically }

procedure TMCForm.AutoSaveBoxClick(Sender: TObject);
begin
    If AutoSaveBox.Checked then MCSave := True
       else MCSave := False;
end;

{ AutoNameEditExit records the name of the MC results file base name }

procedure TMCForm.AutoNameEditExit(Sender: TObject);
begin
    MonteFileBase := AutoNameEdit.Text;
end;

{ The single point calculation seeds the random number generator,             }
{ Performs a MC simulation for the current system, saves all concentration    }
{ results to a text file (if indicated) and then calculates and displays the  }
{ summary statistics in a string grid for user examination.                   }

procedure TMCForm.SinglePointMC1Click(Sender: TObject);

Var   ConcCalc   : integer;     {Number of concentrations being calculated}
      i, j       : integer;     { loop indices }
      ConcArray  : MCConc;

begin
  {Seed the random number generator}
  RandSeed := RSeed;

  ConcCalc := S.Ncomp + S.NSpec;

  If (MonteCarlo(S, MCPoint, MCReps) = 0) then
    begin    {MC simulation returned no errors}
     If MCSave then
        StoreMCFile(MCPoint, MonteFileBase + '.txt', ConcCalc, MCReps);
     For i := 1 to Numconc do begin
        for j := 1 to MCReps do
           ConcArray[j] := MCPoint[j,i];
        CalcStats(ConcArray, MCReps, MCPointSum[i]);
       end;                             {end for i}
        WriteStatGrid(TRUE);
        ClearGraph;
        if MCStatSave then
            StoreMCSummary(MCPointSum, MonteStatFileBase + '.txt', ConcCalc);
     MCDone := True;
     Showmessage('Simulation complete.');
    end                                {End of if MonteCarlo}
    else Showmessage('System failed to converge');

end;                             {End of SinglePointMC1Click }

{When the form is activated, write in the necessary data to the GUI edit fields}
{and clear the graph}

procedure TMCForm.FormActivate(Sender: TObject);
begin
   WriteScreen;
   WriteStatGrid(False);
   ClearGraph;
end;

{This menu option/button calculates the first derivative sensitivity matrix }
{using the CalcSensMat procedure from TiUncertain. If the autosave box is   }
{checked, the matrix is saved in Sensfile}

procedure TMCForm.SensitivityMatrix1Click(Sender: TObject);
begin
   CalcSensMat(S, Sensitivities, DiffX);
   SensDone := TRUE;
   If SensSave then
      SaveSensMat(Sensitivities, SensFile + '.txt', S.NComp+S.NSpec);
   WriteSensMat(Sensitivities, S.NComp + S.NSpec);
   ClearGraph;
end;

{Eventually, this routine will perform a series (sweep) of MC simulations, }
{recording the distributions of one or more concentration at each point   }
{to form a Monte carlo 'surface'.  Currently not coded.}

procedure TMCForm.Surface1Click(Sender: TObject);
begin
   ShowMessage('Sorry- not yet implemented');
end;

{The DiffX variable controls the width of the derivative calculation used in }
{sensitivity calculations.  It is restricted to values > 1e-8 to avoid       }
{round-off error and to values <1 to avoid excess inaccuracy due to          }
{non-linearity.}

procedure TMCForm.DiffXEditExit(Sender: TObject);
begin
   DiffXEdit.Text := WriteRealEdit(DiffXEdit.Text, DiffX, 1e-8, 1);
end;

{MCStatSave is true if Monte Carlo simulation results are to be automatically }
{saved to a text file}

procedure TMCForm.AutoSaveStatBoxClick(Sender: TObject);
begin
   If AutoSaveStatBox.Checked then MCStatSave := True
       else MCStatSave := False;
end;

{SensSave is true if Sensitivity matrices are to be automatically }
{saved to a text file}

procedure TMCForm.AutoSaveSensBoxClick(Sender: TObject);
begin
   If AutoSaveSensBox.Checked then SensSave := True
       else SensSave := False;
end;

{MonteStatFileBase is just the name of the text file used to store summary}
{statistics for a Monte Carlo simulation.  AT some point, it may be used as }
{'base' name for a numbered series of files which would contain MC stats  }
{from a sweep}

procedure TMCForm.StatsNameEditExit(Sender: TObject);
begin
   MonteStatFileBase := StatsNameEdit.Text;
end;

{SensFile is the name of the text file used to store the sensitivity  }
{(first derivative) matrix}

procedure TMCForm.SensFileNameEditExit(Sender: TObject);
begin
   SensFile := SensFileNameEdit.Text;
end;

{When the user selects a species, the frequency distribution is calculated and }
{plotted as a histogram}

procedure TMCForm.GraphSelectChange(Sender: TObject);

Var NConc : integer;                    {number of all species (including comps}
    bin : integer;                      {histogram bin counter}

begin
    {Check to see if MC results have been calculated}
    If (Not MCDone) then begin
       ShowMessage('First you must complete a Monte Carlo calculation.');
       GraphSelect.Itemindex := 0;
       Exit;
      end;

   GraphC := GraphSelect.ItemIndex;     {get the property from the combobox}

   If (GraphC > 0) then begin      {it will be 0 if no property is selected}
     Series1.Title := GraphSelect.Items[GraphC];

     NConc := S.NSpec + S.NComp;
     If CalcDistribution(MCPoint, Frequencies, FreqBins, GraphC, MCReps, NConC) then
       begin
         Series1.Clear;
         for bin := 1 to MaxBins do
            Series1.AddXY(FreqBins[bin], Frequencies[bin]);
       end
      else begin
         ShowMessage('No variation in the data- nothing to plot.');
         GraphSelect.ItemIndex := 0;
         Exit;
        end;                                    {end else}

     end; {End if GraphC > 0}

end;                                     {end GraphSelectChange}

{SingleMCSelect is a drop-down list of components and species}
{The user selects one constraint (total, free or log K) for a limited}
{MC run.  Note- selecting a constraint does not run the MC simulation}

procedure TMCForm.SingleMCSelectChange(Sender: TObject);
begin
   ChosenCon := SingleMCSelect.ItemIndex;
end;

{The single constraint button/menu option allows the user to perform a }
{simulation in which only one constraint is 'randomized'.}

procedure TMCForm.OneVarMCBtnClick(Sender: TObject);
begin
    If (SingleMCSelect.ItemIndex < 1) then
       Showmessage('No constraint has been selected')
      else begin
       OneCon := TRUE;
       SinglePointMC1Click(MCForm);
       OneCon := False;
      end;

end;

{Menu item saves the most recent sensitivity matrix. }

procedure TMCForm.SaveSensitivityMatrix1Click(Sender: TObject);
Var  FMessage : string;

begin
   If SensDone then begin
      SaveSensMat(Sensitivities, SensFile + '.txt', S.NComp+S.NSpec);
      FMessage := 'File ' + SensFile + '.txt saved.';
      Showmessage(FMessage);
     end
    else ShowMessage('No matrix has been calculated.');
end;

{Menu item saves the most recent MC raw results. }

procedure TMCForm.SaveMonteCarloResults1Click(Sender: TObject);
Var  FMessage : string;

begin
   If MCDone then begin
      StoreMCFile(MCPoint, MonteFileBase + '.txt', S.NComp+S.NSpec, MCReps);
      FMessage := 'File ' + MonteFileBase + '.txt saved.';
      Showmessage(FMessage);
     end
    else ShowMessage('No MC simulation has been performed.');
end;

{Menu item saves the most recent MC summary statistics. }

procedure TMCForm.SaveMonteCarloStatistics1Click(Sender: TObject);
Var  FMessage : string;
begin
    If MCDone then begin
      StoreMCSummary(MCPointSum, MonteStatFileBase + '.txt', S.NComp+S.NSpec);
      FMessage := 'File ' + MonteFileBase + '.txt saved.';
      Showmessage(FMessage);
     end
    else ShowMessage('No MC simulation has been performed.');
end;

end.                                     {end of unit MCAccess}
